package org.jsbd.boss.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Enumeration;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.apache.commons.io.FileUtils;
import org.jsbd.boss.domian.channel.FileUploadVo;
import org.jsbd.boss.util.DateUtil;
import org.jsbd.boss.util.ManifestUtils;
import org.jsbd.boss.util.OssUtils;
import org.jsbd.boss.util.PropertiesUtil;
import org.jsbd.boss.util.ReadMGVideoPkg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import edu.hziee.cap.common.util.Md5Utils;

/**
 * 
 * 文件管理
 * 
 * @author <a href="mailto:xupengcheng@zhexinit.com" >徐鹏程</a>
 * @version 1.0.0
 */
@Service
public class FileManager {
	public static final Logger LOGGER = LoggerFactory.getLogger(FileManager.class);

	/**
	 * 上传文件
	 * 
	 * @return
	 */
	public FileUploadVo uploadFile(MultipartFile file) {
		String fileUploadPath = PropertiesUtil.getValue("game_file_upload_path");
		FileUploadVo fileVo = null;
		if (file != null && !file.isEmpty()) {
			File apkFile = null;
			try {
				fileVo = new FileUploadVo();
				String originalFilename = file.getOriginalFilename();
				String fileName = originalFilename.substring(originalFilename.lastIndexOf("/") + 1);
				String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
				// 如果用的是Tomcat服务器，则文件会上传到\\%TOMCAT_HOME%\\webapps\\YourWebProject\\WEB-INF\\upload\\文件夹中
				String fileSaveName = System.currentTimeMillis() + fileName;
				apkFile = new File(fileUploadPath, fileSaveName);
				// 这里不必处理IO流关闭的问题，因为FileUtils.copyInputStreamToFile()方法内部会自动把用到的IO流关掉
				FileUtils.copyInputStreamToFile(file.getInputStream(), apkFile);
				String md5 = Md5Utils.md5Hex(FileUtils.readFileToByteArray(apkFile));
				String day = DateUtil.getCurrentDateStr();
				fileName = day + "/" + md5;
				OssUtils.uploadFile(fileName, file.getInputStream());
				if ("apk".equals(fileType)) {
					fileVo.setPackName(parseApk(apkFile));
				}
				fileVo.setFileSize(apkFile.length());
				fileVo.setMd5(md5);
				fileVo.setFilePath(fileName);
			} catch (Exception e) {
				LOGGER.error(e.getMessage(), e);
			} finally {
				if (apkFile != null) {
					apkFile.setWritable(true);
					apkFile.delete();
				}
			}
		}
		return fileVo;
	}
	
	/**
	 * 上传文件
	 * 
	 * @return
	 */
	public FileUploadVo uploadUpgradeApk(MultipartFile file) {
		String fileUploadPath = PropertiesUtil.getValue("game_file_upload_path");
		FileUploadVo fileVo = null;
		if (file != null && !file.isEmpty()) {
			File apkFile = null;
			try {
				fileVo = new FileUploadVo();
				String originalFilename = file.getOriginalFilename();
				String fileName = originalFilename.substring(originalFilename.lastIndexOf("/") + 1);
				String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
				// 如果用的是Tomcat服务器，则文件会上传到\\%TOMCAT_HOME%\\webapps\\YourWebProject\\WEB-INF\\upload\\文件夹中
				String fileSaveName = System.currentTimeMillis() + fileName;
				apkFile = new File(fileUploadPath, fileSaveName);
				// 这里不必处理IO流关闭的问题，因为FileUtils.copyInputStreamToFile()方法内部会自动把用到的IO流关掉
				FileUtils.copyInputStreamToFile(file.getInputStream(), apkFile);
				String md5 = Md5Utils.md5Hex(FileUtils.readFileToByteArray(apkFile));
				String day = DateUtil.getCurrentDateStr();
				fileName = day + "/" + md5;
				OssUtils.uploadFile(fileName, file.getInputStream());
				if ("apk".equals(fileType)) {
					fileVo.setVersion(parseUpgradeApk(apkFile));
				}
				fileVo.setFileSize(apkFile.length());
				fileVo.setMd5(md5);
				fileVo.setFilePath(fileName);
			} catch (Exception e) {
				LOGGER.error(e.getMessage(), e);
			} finally {
				if (apkFile != null) {
					apkFile.setWritable(true);
					apkFile.delete();
				}
			}
		}
		return fileVo;
	}

	/**
	 * 
	 * parseApk:包名解析
	 * @author <a href="mailto:xupengcheng@zhexinit.com" >徐鹏程</a>
	 * @param f
	 * @return
	 * @throws Exception
	 */
	private String parseApk(File f) throws Exception {
		String packageName = "";
		try {
			ZipFile zip = new ZipFile(f);
			Enumeration<?> enu = zip.entries();
			while (enu.hasMoreElements()) {
				ZipEntry ent = (ZipEntry) enu.nextElement();
				String entName = ent.getName();
				if (entName.equals("AndroidManifest.xml")) {
					Map<String, String> map = ManifestUtils.parseAxml(zip.getInputStream(ent)); // 获取文件信息
					packageName = map.get("package");
				}
			}
			zip.close();
		} catch (Exception e) {
			LOGGER.error("文件解析错误",e);
		}
		return packageName;
	}
	
	/**
	 * 
	 * parseApk:包名解析
	 * @author <a href="mailto:xupengcheng@zhexinit.com" >徐鹏程</a>
	 * @param f
	 * @return
	 * @throws Exception
	 */
	private String parseUpgradeApk(File f) throws Exception {
		String version = "";
		try {
			ZipFile zip = new ZipFile(f);
			Enumeration<?> enu = zip.entries();
			while (enu.hasMoreElements()) {
				ZipEntry ent = (ZipEntry) enu.nextElement();
				String entName = ent.getName();
				if (entName.equals("AndroidManifest.xml")) {
					Map<String, String> map = ManifestUtils.parseAxml(zip.getInputStream(ent)); // 获取文件信息
					version = map.get("versionCode");
				}
			}
			zip.close();
		} catch (Exception e) {
			LOGGER.error("文件解析错误",e);
		}
		return version;
	}

	public FileUploadVo uploadFile(MultipartFile file, String bucketName, String objectNamePrefix) {
		String fileUploadPath = PropertiesUtil.getValue("game_file_upload_path");
		FileUploadVo fileVo = null;
		if (file != null && !file.isEmpty()) {
			File apkFile = null;
			try {
				fileVo = new FileUploadVo();
				String originalFilename = file.getOriginalFilename();
				String fileName = originalFilename.substring(originalFilename.lastIndexOf("/") + 1);

				String fileSaveName = System.currentTimeMillis() + fileName;
				apkFile = new File(fileUploadPath, fileSaveName);
				// 这里不必处理IO流关闭的问题，因为FileUtils.copyInputStreamToFile()方法内部会自动把用到的IO流关掉
				FileUtils.copyInputStreamToFile(file.getInputStream(), apkFile);
				String md5 = Md5Utils.md5Hex(FileUtils.readFileToByteArray(apkFile));
				String day = DateUtil.getCurrentDateStr();
				fileName = objectNamePrefix + "/" + day + "/" + md5;
				OssUtils.uploadFile(bucketName, fileName, file.getInputStream());
				fileVo.setMd5(md5);
				fileVo.setFilePath(fileName);
			} catch (Exception e) {
				LOGGER.error(e.getMessage(), e);
			} finally {
				if (apkFile != null) {
					apkFile.setWritable(true);
					apkFile.delete();
				}
			}
		}
		return fileVo;
	}

	public FileUploadVo uploadFileByName(MultipartFile file, String bucketName, String objectName, String fileMd5) {
		String fileUploadPath = PropertiesUtil.getValue("game_file_upload_path");
		FileUploadVo fileVo = null;
		if (file != null && !file.isEmpty()) {
			File apkFile = null;
			try {
				fileVo = new FileUploadVo();
				String originalFilename = file.getOriginalFilename();
				String fileName = originalFilename.substring(originalFilename.lastIndexOf("/") + 1);

				String fileSaveName = System.currentTimeMillis() + fileName;
				apkFile = new File(fileUploadPath, fileSaveName);
				// 这里不必处理IO流关闭的问题，因为FileUtils.copyInputStreamToFile()方法内部会自动把用到的IO流关掉
				FileUtils.copyInputStreamToFile(file.getInputStream(), apkFile);
				String md5 = Md5Utils.md5Hex(FileUtils.readFileToByteArray(apkFile));

				if (!md5.equals(fileMd5)) {
					LOGGER.warn("file [{}] is lacking", objectName);
					return null;
				}
				OssUtils.uploadFile(bucketName, objectName + "/" + fileName, file.getInputStream());
				fileVo.setMd5(md5);
				fileVo.setFilePath(fileName);
			} catch (Exception e) {
				LOGGER.error(e.getMessage(), e);
			} finally {
				if (apkFile != null) {
					apkFile.setWritable(true);
					apkFile.delete();
				}
			}
		}
		return fileVo;
	}

	public FileUploadVo uploadFile(byte[] fileData, String bucketName, String objectName, String fileName, String fileMd5) {
		String fileUploadPath = PropertiesUtil.getValue("game_file_upload_path");
		FileUploadVo fileVo = null;
		if (fileData != null && fileData.length > 0) {
			File apkFile = null;
			InputStream in = null;
			try {
				fileVo = new FileUploadVo();

				apkFile = new File(fileUploadPath, fileName);
				FileUtils.writeByteArrayToFile(apkFile, fileData);
				String md5 = Md5Utils.md5Hex(FileUtils.readFileToByteArray(apkFile));

				if (!md5.equals(fileMd5)) {
					LOGGER.warn("md5 is not save and file [{}] is lacking", objectName);
					return null;
				}

				in = new FileInputStream(apkFile);
				OssUtils.uploadFile(bucketName, objectName, in);
				fileVo.setMd5(md5);
				fileVo.setFilePath(objectName);
			} catch (Exception e) {
				LOGGER.error(e.getMessage(), e);
			} finally {
				if (in != null) {
					try {
						in.close();
					} catch (IOException e) {
						LOGGER.error("Any error msg that u want to write", e);
					}
				}

				if (apkFile != null) {
					apkFile.setWritable(true);
					apkFile.delete();
				}
			}
		}
		return fileVo;
	}
	
	/**
	 * 上传咪咕视频包并解析
	 * 
	 * @param file
	 * @return
	 */
	public FileUploadVo uploadMiguVideoFile(MultipartFile file) {
		String fileUploadPath = this.getClass().getClassLoader().getResource("").getPath();
		System.out.println("-----------fileUploadPath-------=" + fileUploadPath);
		String jarPath = fileUploadPath.substring(0, fileUploadPath.length()-5);
		FileUploadVo fileVo = null;
		if (file != null && !file.isEmpty()) {
			File apkFile = null;
			File decodeDir = null;
			String filename = null;
			String ext = null;
			try {
				fileVo = new FileUploadVo();
				String originalFilename = file.getOriginalFilename();
				filename = originalFilename.substring(0, originalFilename.lastIndexOf("."));
				ext = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
				// 如果用的是Tomcat服务器，则文件会上传到\\%TOMCAT_HOME%\\webapps\\YourWebProject\\WEB-INF\\upload\\文件夹中
				apkFile = new File(fileUploadPath, originalFilename);
				System.out.println("-----------apkFile.getAbsolutePath()-------=" + apkFile.getAbsolutePath());
				System.out.println("-----------apkFile.getName()---------=" + apkFile.getName());
				// 这里不必处理IO流关闭的问题，因为FileUtils.copyInputStreamToFile()方法内部会自动把用到的IO流关掉
				FileUtils.copyInputStreamToFile(file.getInputStream(), apkFile);
				System.out.println("-----------apkFile.getCanonicalPath()-------=" + apkFile.getCanonicalPath());
				if ("apk".equals(ext)) {
					fileVo.setPackageInfo(ReadMGVideoPkg.readPackageInfo(jarPath, apkFile.getCanonicalPath(), apkFile.getName()));
				}
			} catch (Exception e) {
				LOGGER.error(e.getMessage(), e);
			} finally {
				if (apkFile != null) {
					apkFile.setWritable(true);
					apkFile.delete();
				}
				decodeDir = new File(fileUploadPath, filename);
				if (decodeDir != null) {
					deleteFile(decodeDir);
				}
			}
		}
		return fileVo;
	}
	
	private static void deleteFile(File file){
        if (file.isFile()){
            file.delete();
        }else{
            String[] childFilePath = file.list();
            for (String path:childFilePath){
                File childFile= new File(file.getAbsoluteFile() + File.separator + path);
                deleteFile(childFile);
            }
            file.delete();
        }
    }
	
}
